/*
 * handleDownload function
 * Info:
 * This function is used to handle incoming download requests.
 * e.g. a user wants to download a file from the server.
 */

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h> //memory map files dingen
#include <semaphore.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h> //to determine filesize with fstat()
#include <string.h>
#include <semaphore.h>
#include <sys/uio.h>
#include "hfile.h"

//int sendData(long chunkSize, long chunkRemain, long unsigned fileSize, int clientFd, int downFd, int comChannel, int fileFd, semList semaphores[]);

int handleDownload(int clientNo, clientInfo client[])
{
    //open the requested file, if it does not exist, give an error
    if((client[clientNo].iFileFd = open(client[clientNo].filename, O_RDONLY))<0)
    {
        perror("can't open file");
        //write(comChannelfd, "ERROROPENFILE\0", 14);
        close(client[clientNo].iFileFd);
    }
    //end of file opening

    //calculate the filesize (this must be known so we know when we're done)
    client[clientNo].luFileSize = lseek(client[clientNo].iFileFd, 0, SEEK_END);
    lseek(client[clientNo].iFileFd, 0, SEEK_SET);
    printf("iFileFd: %d\n", client[clientNo].iFileFd);
    printf("fileSize: %lu\n", client[clientNo].luFileSize);
    //end of calculation
    //go to sendData to start sending data to client.
    sendData(client[clientNo].clientNo, client);
    return 0;
}
//end of handleDownload

int sendData(int clientNo, clientInfo client[])
{
    client[clientNo].totalSent = 0;
    client[clientNo].amountRead = 0;
    client[clientNo].amountWritten = 0;
    printf("fileSize: %lu\n", client[clientNo].luFileSize);
    printf("sendData reached by clientNo: %d\n", clientNo);
    //place a notification in the client map that FSP is ready to send
    lseek(client[clientNo].iMapFd, 0, SEEK_SET);
    if((write(client[clientNo].iMapFd, "READY\0", 6))<0)
    {
        perror("could not write to map");
    }
    //notify that FSP is ready to send data
    sem_post(client[clientNo].semaphoreFull);
    printf("posted semaphore\n");

    printf("client[clientNo].iFileFd = %d\n", client[clientNo].iFileFd);
    //wait for a signal that i can start sending data
    sem_wait(client[clientNo].semaphoreEmpty);
    //stay is this loop while totalSent < the filesize that needs to be sent
    while(client[clientNo].totalSent < client[clientNo].luFileSize)
    {
        //make sure you read and write everything from the starting position per FD
        lseek(client[clientNo].iMapFd, 0, SEEK_SET);
        printf("entered download loop, filefd: %d, clientNo: %d\n", client[clientNo].iFileFd, client[clientNo].clientNo);
        //empty the tempBuffer for this client
        bzero(client[clientNo].tempBuff, CHUNKSIZE);
        //read the data from the iFileFd to the tempBuff, with CHUNKSIZE per time if > 0, else it will read the amount of bytes left
        if((client[clientNo].amountRead = read(client[clientNo].iFileFd, client[clientNo].tempBuff, CHUNKSIZE)) > 0)
        {
            //write the data to the user map file from tempBuff to iMapFd
            if(client[clientNo].amountWritten = (write(client[clientNo].iMapFd, client[clientNo].tempBuff, client[clientNo].amountRead))!=client[clientNo].amountRead)
            {
                perror("incorrect amount of bytes was written!");
                return 0;
            }
            printf("cMap: %s\n", client[clientNo].cMapFile);
            printf("amount read: %lu\n", client[clientNo].amountRead);
            //add the amountRead to the totalSent
            client[clientNo].totalSent += client[clientNo].amountRead;
            printf("total written: %lu\n", client[clientNo].totalSent);
            //notify CHP that data is ready
            sem_post(client[clientNo].semaphoreFull);

            printf("gonna wait for my semaphore.\n");
            //wait for CHP to finish sending it to the client and notify us he is ready
            sem_wait(client[clientNo].semaphoreEmpty);
        }
    }
    //post the last bit of data.
    sem_post(client[clientNo].semaphoreFull);
    //sleep for 1 sec, sync time. (do we need more semaphores per client?)
    close(client[clientNo].iFileFd);
    sleep(1);
    return 0;
}